package cn.player.act;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import cn.player.R;
import cntv.player.core.util.LogUtil;

public class SocketClientActivity extends BaseActivity {

    private static final int MSG_CONNECT_SUCCESS = 0;
    private static final int MSG_CONNECT_FAILED = 1;
    private static final int TYPE_MSG_RECEIVE_ALL = 101;
    private static final int TYPE_MSG_RECEIVE_PART = 102;
    private EditText etMsg;
    private Button btnSend;
    private Button btnSendNotReceive;
    private Button btnSendAndReceiverAll;
    private Button btnReceiverPart;
    private TextView tvMsg, tvMsgPart;
    private ProgressDialog progressDialog;

    private OnClickListener mOnClickListener;

    private Socket mSocket;
    private InputStream mSocketIs;
    private OutputStream mSocketOs;


    private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_CONNECT_SUCCESS:
                    dismissProgressDialog();
                    String result = (String) msg.obj;
//				Toast.makeText(SocketClientActivity.this, result, Toast.LENGTH_SHORT).show();
                    int type = msg.arg1;
                    switch (type) {
                        case TYPE_MSG_RECEIVE_ALL:
                            tvMsg.setTextColor(getResources().getColor(R.color.black));
                            tvMsg.setText(result);
                            break;
                        case TYPE_MSG_RECEIVE_PART:
                            tvMsgPart.setTextColor(getResources().getColor(R.color.black));
                            tvMsgPart.setText(result);
                            break;
                        default:
                            break;
                    }
                    break;
                case MSG_CONNECT_FAILED:
                    dismissProgressDialog();
                    String result2 = (String) msg.obj;
//				Toast.makeText(SocketClientActivity.this, result, Toast.LENGTH_SHORT).show();
                    tvMsg.setTextColor(getResources().getColor(R.color.red));
                    tvMsg.setText(result2);
                    break;

                default:
                    break;
            }
        }

    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.socket_client_view);

        findViews();
        setListeners();
    }

    private void findViews() {
        // TODO Auto-generated method stub
        etMsg = (EditText) findViewById(R.id.et_msg);
        btnSend = (Button) findViewById(R.id.btn_send);
        btnSendNotReceive = (Button) findViewById(R.id.btn_send_not_receive);
        btnSendAndReceiverAll = (Button) findViewById(R.id.btn_send_receive_all);
        btnReceiverPart = (Button) findViewById(R.id.btn_receive_part);
        tvMsg = (TextView) findViewById(R.id.tv_response_msg);
        tvMsgPart = (TextView) findViewById(R.id.tv_response_part_msg);
    }

    private void setListeners() {
        // TODO Auto-generated method stub
        mOnClickListener = new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                switch (v.getId()) {
                    case R.id.btn_send:
                        showProgressDialog();
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                if (!connect()) {
                                    return;
                                }
                                send("cn" + etMsg.getText().toString());
                            }
                        }).start();
                        break;
                    case R.id.btn_send_not_receive:
                        showProgressDialog();
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                if (!connect()) {
                                    return;
                                }
                                send(etMsg.getText().toString());
                            }
                        }).start();
                        break;
                    case R.id.btn_send_receive_all:
                        showProgressDialog();
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
//							uploadPhoto();
                                if (!connect()) {
                                    return;
                                }
                                String msg = etMsg.getText().toString();
                                if (!send(msg)) {
                                    return;
                                }
                                String result = readAll();
                                LogUtil.i("zl", "result = " + result);
                                if (!TextUtils.isEmpty(result)) {
                                    notifySuccess(result, TYPE_MSG_RECEIVE_ALL);
                                }
                            }
                        }).start();
                        break;
                    case R.id.btn_receive_part:
                        showProgressDialog();
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                if (!connect()) {
                                    return;
                                }
                                String result = read();
                                LogUtil.i("zl", "result = " + result);
                                if (!TextUtils.isEmpty(result)) {
                                    notifySuccess(result, TYPE_MSG_RECEIVE_PART);
                                }
                            }
                        }).start();
                        break;

                    default:
                        break;
                }
            }
        };
        btnSend.setOnClickListener(mOnClickListener);
        btnSendNotReceive.setOnClickListener(mOnClickListener);
        btnSendAndReceiverAll.setOnClickListener(mOnClickListener);
        btnReceiverPart.setOnClickListener(mOnClickListener);
    }

    /**
     * 显示正在上传加载框
     */
    private void showProgressDialog() {
        progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("正在加载,请稍候...");
        progressDialog.show();
    }

    /**
     * 通知成功消息
     *
     * @param successMsg
     * @param type
     */
    private void notifySuccess(String successMsg, int type) {
        Message msg = handler.obtainMessage();
        msg.what = MSG_CONNECT_SUCCESS;
        msg.obj = successMsg;
        msg.arg1 = type;
        handler.sendMessage(msg);
    }

    /**
     * 通知失败消息
     *
     * @param failMsg
     */
    private void notifyFailed(String failMsg) {
        close();
//		connect();//socket重新连接,如果一起连接失败，容易导致列循环
        Message msg = handler.obtainMessage();
        msg.what = MSG_CONNECT_FAILED;
        msg.obj = failMsg;
        handler.sendMessage(msg);
    }

    /**
     * 隐藏正在上传加载框
     */
    private void dismissProgressDialog() {
        if (progressDialog != null) {
            progressDialog.dismiss();
        }
    }

    /**
     * 检查socket是否保持着连接
     *
     * @return
     */
    private boolean checkConnection() {
        return mSocket != null && mSocket.isConnected();
    }

    /**
     * socket连接方法
     *
     * @return 返回是否连接成功
     */
    private boolean connect() {
        try {
            if (checkConnection()) {
                LogUtil.i("zl", "服务器已连接");
                return true;
            }
            mSocket = new Socket("172.21.68.248", 9860);// 与服务器建立连接
            LogUtil.i("zl", "服务器连接成功 connect = " + mSocket.getInetAddress().toString());

            mSocketIs = mSocket.getInputStream();// 获取服务器发回的状态
            mSocketOs = mSocket.getOutputStream();
            return true;
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            LogUtil.i("zl", "连接失败，请重试! e = " + e.getMessage());
            notifyFailed("连接失败，" + e.getMessage());
            return false;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            LogUtil.i("zl", "连接失败，请重试! e = " + e.getMessage());
            notifyFailed("连接失败，" + e.getMessage());
            return false;
        }
    }

    /**
     * 往服务器发送消息
     *
     * @param msg
     * @return 返回是否发送成功
     */
    private boolean send(String msg) {
        try {
            if (mSocketOs != null) {
                mSocketOs.write(msg.getBytes("utf-8"));
                mSocketOs.flush();
                notifySuccess("发送消息成功", TYPE_MSG_RECEIVE_ALL);
                return true;
            } else {
                LogUtil.i("zl", "发送失败, OutputStream == null");
//				notifyFailed("发送失败, OutputStream == null");
                return false;
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            LogUtil.i("zl", "发送失败, e = " + e.getMessage());
            notifyFailed("发送失败," + e.getMessage());
            return false;
        }
    }

    /**
     * 读取服务器返回的消息(读取1kb大小数据)
     *
     * @return
     */
    public String readAll() {
        try {
            byte[] temp = new byte[1024];
            LogUtil.i("zl", "input.available() = " + mSocketIs.available());
            int nRead = mSocketIs.read(temp);
            if (nRead != -1) {
                return new String(temp, 0, nRead, "utf-8");
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            LogUtil.i("zl", "读取失败，请重试! e = " + e.getMessage());
            notifyFailed("读取失败," + e.getMessage());
        }
        return null;
    }

    /**
     * 读取服务器返回的消息(读取4byte大小数据)
     *
     * @return
     */
    public String read() {
        try {
            byte[] temp = new byte[4];
            LogUtil.i("zl", "input.available() = " + mSocketIs.available());
            // 如果读到流的结尾后，线程一直阻塞在这里，也就是一直等着服务器发过来新的数据读取。
            // 这是由于socket服务端的OutputStream并没有关闭，所以这里并不认为流已经结束。
            // 这里只要服务端输出流在flush()之后正确关闭即可
            int nRead = mSocketIs.read(temp, 0, 4);
            if (nRead != -1) {
                return new String(temp, 0, nRead, "utf-8");
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            LogUtil.i("zl", "读取失败，请重试! e = " + e.getMessage());
            notifyFailed("读取失败," + e.getMessage());
        }

        return null;
    }

    /**
     * 将Byte数组转换为int类型 *
     *
     * @param byteArray 长度必须是4
     * @return
     */
    private int byteArray2Int(byte[] byteArray) {
        if (byteArray == null || byteArray.length != 4) {
            throw new IllegalArgumentException("The byte arrays length must be 4 !");
        }
        int value = 0;
        value += (byteArray[0] & 0x000000FF) << 24;
        value += (byteArray[1] & 0x000000FF) << 16;
        value += (byteArray[2] & 0x000000FF) << 8;
        value += (byteArray[3] & 0x000000FF) << 0;
        return value;
    }

    private int readInteger(InputStream input) throws IOException {
        byte[] temp = new byte[4];
        // 如果读到流的结尾后，线程一真阻塞在这里，也就是一直在等着再有新数据读。
        // 这是由于socket服务端的OutputStream并没有关闭，所以这里并不认为流已经结束。
        // 这里只要服务端输出流在flush()之后正确关闭即可
        int nRead = input.read(temp, 0, 4);
        if (-1 == nRead) {
            throw new IOException("CommonUtils::readInteger$trigger");
        }
        return byteArray2Int(temp);
    }

    /**
     * 关闭流和socket
     */
    private void close() {
        try {
            if (mSocketOs != null) {
                mSocketOs.close();
                mSocketOs = null;
                LogUtil.i("zl", "client outputStream closed...");
            }
            if (mSocketIs != null) {
                mSocketIs.close();
                mSocketIs = null;
                LogUtil.i("zl", "client inputStream closed...");
            }
            if (mSocket != null) {
                mSocket.close();
                mSocket = null;
                LogUtil.i("zl", "client socket closed...");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        close();
    }

    /**
     * 从本地读取一张图片发送至服务器
     *
     * @param os
     */
    private void writeToServer(OutputStream os) {
        InputStream is = null;
        try {
            is = getAssets().open("beauty.jpg");// 获取asset目录下的图片流
            // 创建一个字节数组
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = is.read(buf)) != -1) {// 每次读取数据1024个字节,直到没有数据可读时==-1
                // 将每次读取到的输入按指定大小写入输出流中
                os.write(buf, 0, len);
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}
